use std::{env, fs};
use pest::Parser;
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "grammar.pest"]
struct SysYParser;

#[derive(Debug)]
pub enum Token {
    Ident(String,usize),
    Integer(i64,usize),
    RuleToken(String, String, usize),
    Error(String, usize)
}

fn main() {
    // 收集命令行参数
    let args: Vec<String> = env::args().collect();

    // 检查是否提供了文件名
    if args.len() < 2 {
        eprintln!("Usage: {} <filename>", args[0]);
        std::process::exit(1);
    }

    // 获取文件名
    let filename = &args[1];

    // 读取输入文件
    let input = fs::read_to_string(filename).expect("Failed to read file");

    // 词法分析
    let tokens = tokenize(&input);

    // 如果只发生错误只输出错误token
    let mut has_error = false;
    for token in tokens.iter().clone() {
        match token {
            Token::Error(char, line) => {
                eprintln!("Error type A at Line {}:Mysterious character \"{}\".",line,char);
                has_error = true;
            }
            _ => {} // 忽略其他所有token
        }
    }

    // 如果有错误 则结束程序
    if has_error {
        return;
    }
    for token in tokens {
        match token {
            Token::Ident(name,line) => {
                eprintln!("IDENT {} at Line {}.", name,line);
            },
            Token::Integer(value,line) => {
                eprintln!("INTEGER_CONST {} at Line {}.", value,line);
            },
            Token::RuleToken(rule_name, value,line) => {
                eprintln!("{} {} at Line {}.", rule_name, value,line);
            }
            Token::Error(char, line) => {
                println!("Error type A at Line {}:Mysterious character \"{}\".",line,char);
            }
        }
    }
}

pub fn tokenize(input: &str) -> Vec<Token> {
    let pairs = SysYParser::parse(Rule::tokens, input)
        .unwrap_or_else(|e| {
            eprintln!("Parse error: {}", e);
            panic!("Parse error: {}", e)
        })
        .next()
        .unwrap();

    pairs.into_inner()
        .filter_map(|p| {
            // 过滤掉EOI规则
            match p.as_rule() {
                Rule::TOKEN => {
                    let inner_pair = p.into_inner().next().unwrap();
                    match inner_pair.as_rule() {
                        Rule::IDENT => Some(Token::Ident(inner_pair.as_str().to_string(),inner_pair.line_col().0)),
                        Rule::INTEGER_CONST => {
                            let num_str = inner_pair.as_str();

                            // 处理不同进制的数字
                            let value = if num_str.starts_with("0x") || num_str.starts_with("0X") {
                                i64::from_str_radix(&num_str[2..], 16).unwrap()
                            } else if num_str.starts_with('0') && num_str.len() > 1 {
                                // 八进制数处理
                                i64::from_str_radix(num_str, 8).unwrap()
                            } else {
                                num_str.parse().unwrap()
                            };

                            Some(Token::Integer(value,inner_pair.line_col().0))
                        },
                        Rule::ERROR => {
                            // 错误token
                            Some(Token::Error(inner_pair.as_str().to_string(), inner_pair.line_col().0))
                        },
                        _ => {
                            // 对于其他所有规则，直接使用规则名作为token类型
                            let rule_name = format!("{:?}", inner_pair.as_rule());
                            Some(Token::RuleToken(rule_name, inner_pair.as_str().to_string(),inner_pair.line_col().0))
                        }
                    }
                },
                _ => None, // 忽略其他不需要的规则
            }
        })
        .collect()
}